package com.ferry.transport.netty.client;

import com.ferry.registry.domain.registry.RegistryMetaData;
import com.ferry.registry.domain.service.ServiceAddress;
import com.ferry.registry.domain.service.ServiceMetaData;
import com.ferry.registry.listener.NotifyListener;
import com.ferry.registry.listener.OfflineListener;
import com.ferry.registry.service.AbstractRegistryService;
import com.ferry.registry.service.IRegistryService;
import com.ferry.transport.api.Connection;
import com.ferry.transport.api.ConnectionManager;
import com.ferry.transport.api.Directory;
import com.ferry.transport.api.UnResolvedAddress;
import com.ferry.transport.netty.consumer.ConnectionWatcher;
import com.ferry.transport.netty.consumer.Connector;
import com.ferry.transport.netty.consumer.DefaultConnectionWatcher;
import com.ferry.transport.netty.provider.FerryProvider;
import org.apache.commons.lang3.StringUtils;

import java.util.List;

/**
 * Created by daiyong
 */
public class DefaultConsumerClient implements ConsumerClient{

	private IRegistryService registryService;

	private String appName;

	private Connector<Connection> connector;

	public DefaultConsumerClient(IRegistryService registryService, String appName, Connector<Connection> connector) {
		this.registryService = registryService;
		this.appName = appName;
		this.connector = connector;
	}

	@Override
	public String appName() {
		return appName;
	}

	@Override
	public Connector<Connection> connector() {
		return connector;
	}

	@Override
	public void setConnector(Connector<Connection> connector) {
		this.connector = connector;
	}

	@Override
	public IRegistryService registryService() {
		return registryService;
	}

	/**
	 * 获取服务
	 * @param directory
	 * @return
	 */
	@Override
	public List<RegistryMetaData> lookup(Directory directory) {
		ServiceMetaData serviceMetaData =
				new ServiceMetaData(directory.getGroup(), directory.getServiceProviderName(), directory.getVersion());

		return registryService.query(serviceMetaData);
	}

	@Override
	public ConnectionWatcher watchConnections(Class<?> interfaceClass) {
		return watchConnections(interfaceClass, "1.0");
	}

	@Override
	public ConnectionWatcher watchConnections(Class<?> interfaceClass, String version) {
		FerryProvider annotation = interfaceClass.getAnnotation(FerryProvider.class);
		Directory directory = new Directory();
		directory.setGroup(annotation.group());
		directory.setServiceProviderName(annotation.serviceName());
		directory.setVersion(StringUtils.isNotBlank(annotation.version()) ? annotation.version() : version);
		return watchConnections(directory);
	}

	@Override
	public ConnectionWatcher watchConnections(Directory directory) {
		DefaultConnectionWatcher watcher = new DefaultConnectionWatcher(directory);
		watcher.setConnector(connector);
		watcher.setConsumerClient(this);
		watcher.setConnectionManager(connector.connectionManager());
		watcher.start();
		return watcher;
	}

	@Override
	public boolean awaitConnections(Class<?> interfaceClass, long timeoutMillis) {
		return awaitConnections(interfaceClass, "1.0", timeoutMillis);
	}

	@Override
	public boolean awaitConnections(Class<?> interfaceClass, String version, long timeoutMillis) {
		ConnectionWatcher watcher = watchConnections(interfaceClass, version);
		return watcher.waitForAvailable(timeoutMillis);
	}

	@Override
	public boolean awaitConnections(Directory directory, long timeoutMillis) {
		ConnectionWatcher watcher = watchConnections(directory);
		return watcher.waitForAvailable(timeoutMillis);
	}

	@Override
	public void subscribe(Directory directory, NotifyListener listener) {
		ServiceMetaData serviceMetaData =
				new ServiceMetaData(directory.getGroup(), directory.getServiceProviderName(), directory.getVersion());
		registryService.subscribe(serviceMetaData, listener);
	}

	@Override
	public void offlineListening(UnResolvedAddress address, OfflineListener listener) {
		ServiceAddress serviceAddress = new ServiceAddress(address.getIp(), address.getPort());
		((AbstractRegistryService)registryService).offlineListening(serviceAddress, listener);
	}

	@Override
	public void shutdownGracefully() {
		registryService.shutdownGracefully();
		connector.shutdownGracefully();
	}
}
